from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User, AddressInfo
from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView
from .serializers import UserRegisterSerializer, UserInfoSerializer, UserEmailSerializer, serializers
from rest_framework.permissions import IsAuthenticated
from meiduo_mall.utils import dict_serializer
from . import constants
from rest_framework import status
from rest_framework.viewsets import ModelViewSet
from .serializers import AddressCreateSerializer
from rest_framework.decorators import action
from django_redis import get_redis_connection
from goods.models import SKU
from goods.serializers import SKUListSerializer
from rest_framework_jwt.views import ObtainJSONWebToken
from carts.utils import merge_cookie_to_redis


class UsernameCountView(APIView):
    def get(self, request, username):
        # 判断用户名是否存在：根据用户名查询，并统计个数
        count = User.objects.filter(username=username).count()

        return Response({
            "username": username,
            "count": count
        })


class MobileCountView(APIView):
    def get(self, request, mobile):
        # request.user
        count = User.objects.filter(mobile=mobile).count()
        return Response({
            "mobile": mobile,
            "count": count
        })


# class UserRegisterView(APIView):
#     def post(self,request):
#         #创建用户对象
class UserRegisterView(CreateAPIView):
    # 当前进行创建操作，指定序列化器类型
    serializer_class = UserRegisterSerializer

    def get(self, request):
        user = User.objects.get(pk=3)
        # 状态保持
        from rest_framework_jwt.settings import api_settings
        # 获取载荷方法
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # 获取签名方法
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        # 计算载荷
        payload = jwt_payload_handler(user)
        # 计算签名，生成jwt字符串
        token = jwt_encode_handler(payload)

        return Response(token)


class UserInfoView(RetrieveAPIView):
    # 查询一个retrieve：默认实现是根据主键查询一个对象
    # 此处，不需要根据主键查询对象
    # 当前业务逻辑为：个人信息，表示当前登录用户的基本信息
    # retrieve方法中调用了get_object()，默认是根据主键查询对象
    # 不希望根据主键查询对象，即不使用默认的实现代码，则重写此方法
    def get_object(self):
        # 返回当前登录的用户对象
        return self.request.user

    # 访问此类的视图，需要先登录
    permission_classes = [IsAuthenticated]

    # queryset = User.objects.all()
    serializer_class = UserInfoSerializer


class UserEmailView(UpdateAPIView):
    # queryset =
    # 不需要根据主键查询对象，而是获取当前登录的用户对象
    permission_classes = [IsAuthenticated]

    def get_object(self):
        return self.request.user

    serializer_class = UserEmailSerializer


class UserEmailVerifyView(APIView):
    def get(self, request):
        # 接收加密信息
        token = request.query_params['token']

        # 验证，获取用户编号
        dict1 = dict_serializer.loads(token, constants.EMAIL_ACTIVE_EXPIRES)

        # 修改当前登录用户的邮箱状态属性
        if dict1 is None:
            return Response({'message': '激活失败'}, status=status.HTTP_400_BAD_REQUEST)

        user = User.objects.get(pk=dict1.get('user_id'))
        user.email_active = True
        user.save()

        return Response({'message': '修改成功'})


class AddressModelViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated]

    # list=========>被重写
    # retrieve====>不需要
    # create======>直接使用，但是在序列化器中重写了create()方法
    # update=====>直接使用
    # destroy
    # queryset = AddressInfo.objects.all()
    def get_queryset(self):
        return self.request.user.addresses.all()

    serializer_class = AddressCreateSerializer

    def list(self, request, *args, **kwargs):
        user = request.user

        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)

        return Response({
            'user_id': user.id,
            'default_address_id': user.default_address_id,
            'limit': constants.USER_ADDRESS_COUNTS_LIMIT,
            'addresses': serializer.data,
        })

    # 新功能：设置默认收货地址，修改标题，本质为修改操作
    @action(methods=['PUT'], detail=True)  # /addresses/(?P<pk>\d+)/status/
    def status(self, request, pk):
        # 设置默认收货地址
        user = request.user
        user.default_address_id = pk
        user.save()
        return Response({'message': 'ok'})

    @action(methods=['PUT'], detail=True)  # /addresses/(?P<pk>\d+)/title/
    def title(self, request, pk):
        # 修改收货地址的标题属性
        title = request.data.get('title')
        address = self.get_object()
        address.title = title
        address.save()
        return Response({'message': 'ok'})


class HistoryView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        # 从redis中读取商品编号，查询商品对象
        # 连接redis
        redis_cli = get_redis_connection('browse_history')
        # 创建键
        key = 'history%d' % request.user.id
        # 读取编号列表
        sku_ids = redis_cli.lrange(key, 0, -1)
        # 从redis中读取的数据为bytes类型，需要转换为int
        sku_ids = [int(sku_id) for sku_id in sku_ids]
        # 查询商品对象
        skus = []
        for sku_id in sku_ids:
            skus.append(SKU.objects.get(pk=sku_id))
        # 序列化输出
        serializer = SKUListSerializer(skus, many=True)
        return Response(serializer.data)

    def post(self, request):
        # 向redis中添加商品编号
        # 接收
        sku_id = request.data.get('sku_id')

        # 验证
        if not all([sku_id]):
            raise serializers.ValidationError('缺少商品编号参数')
        try:
            sku = SKU.objects.get(pk=sku_id)
        except:
            raise serializers.ValidationError('商品编号无效')

        # 保存：写redis
        redis_cli = get_redis_connection('browse_history')
        key = 'history%d' % request.user.id
        # 1.删除当前元素
        redis_cli.lrem(key, 0, sku_id)
        # 2.加入到最前
        redis_cli.lpush(key, sku_id)
        # 3.限制5个
        redis_cli.ltrim(key, 0, 4)

        # 响应
        return Response({'sku_id': sku_id})


class LoginView(ObtainJSONWebToken):
    def post(self, request, *args, **kwargs):
        # 重写父类的方法，在这里调用父类的方法，重用原有逻辑
        response = super().post(request, *args, **kwargs)

        # # 判断用户是否登录成功
        if 'user_id' in response.data:
            # 获取当前用户的编号
            user_id = response.data.get('user_id')
            # 增加新逻辑：当用户登录成功后合并购物车
            response = merge_cookie_to_redis(request, response, user_id)

        return response
